ToT 思维树 Tree of Thoughts
ToT = Tree of Thoughts(思维树)。把 CoT 的一条线性推理链,扩展成一棵可以分叉、评估、剪枝的树,并用经典搜索算法(BFS / DFS)来遍历它。 关键在于节点是什么:不是一个孤立的 though…
ToT:Tree of Thoughts 思维树
阅读提示 面向了解 CoT(思维链)并对传统搜索算法(BFS / DFS / Beam Search)有印象的学习者。 本篇的主线是:ToT 就是把经典搜索算法搬到「思考步骤」这种节点上。 ⚠️ = 常见陷阱 🆚 = 对比说明 💡 = 选择建议
目录
- 一、一句话定义
- 二、最小示例:一棵被剪过枝的树
- 三、机制:四个必备组件
- 四、🆚 和 CoT、Self-Consistency 的区别
- 五、⚠️ 核心陷阱:评估函数是整个方法的命门
- 六、什么时候用
- 七、复习重点
核心概念 ToT = Tree of Thoughts(思维树)。把 CoT 的一条线性推理链,扩展成一棵可以分叉、评估、剪枝的树,并用经典搜索算法(BFS / DFS)来遍历它。
关键在于节点是什么:不是一个孤立的 thought,而是一个 state(部分解)——原论文定义为
s = [x, z₁…zᵢ],即「原始问题 + 到目前为止的整条 thought 序列」。边才是一个新的 thought。这一点决定了评估器评的是「当前这个局面有没有希望」,而不是「这句话说得好不好」。
一、一句话定义
不要只沿着一条思路推理,而是同时铺开多条思路,评估后保留好的、淘汰差的,再继续展开。
二、最小示例:一棵被剪过枝的树
Problem
|
-------------------
| | |
思路A 思路B 思路C
| | |
A1 B1 C1
A2 B2
|
B3实际运行时每个节点都会被打分,低分分支直接剪掉:
读图顺序:从顶部「问题」出发,第一层生成三个候选思路并各自打分,思路 C(0.2)当场剪掉;沿保留的分支继续展开,B2 得分最高,最终在 B3 拿到答案。实线框是活跃分支,灰虚线框是被评估函数剪掉的分支。
一轮循环固定是四步:
生成候选思路(Propose)
↓
评估(Evaluate)
↓
保留好的 / 淘汰差的(Prune)
↓
继续展开(Expand)三、机制:四个必备组件
实现一个 ToT,缺一不可的是这四样:
| 组件 | 作用 | 常见做法 |
|---|---|---|
| Thought 定义 | 一个「思考步骤」的粒度是什么 | 一行算式、一个中间方案、一句话 |
| Generator | 从当前节点生成 k 个候选 | 高温度采样,或一次性让模型列 k 个方案 |
| Evaluator | 给节点打分或排序 | 模型自评(打分 / 两两比较)、规则校验、跑代码 |
| 搜索策略 | 决定展开顺序和保留数量 | BFS(保留 top-b 层层推进)、DFS(走到底再回溯)、Beam Search |
它本质上是把传统搜索搬到语言推理上,但节点的含义没有变——两边都是「状态」:
传统搜索的节点:状态(棋盘局面、地图位置)
ToT 的节点: 状态 = 原问题 + 已经走过的全部 thought,即一个「部分解」
ToT 的边: 一个新的 thought(一个推理步骤)⚠️ 把节点理解成「一个孤立的 Thought」 这是读 ToT 最常见的偏差,也是本笔记旧版本犯的错。如果节点只是一句孤立的想法,评估器就只能评「这句话听起来靠不靠谱」——那正是第五节要批判的失效方式。
原论文里节点是
s = [x, z₁…zᵢ]:带着完整历史的部分解。以 24 点为例,走完4 + 9 = 13之后,节点不是「4+9=13」这句话,而是「剩余数字 13, 5, 6」这个局面。评估器拿到的是局面,才能判断「用 13、5、6 还凑不凑得出 24」。实现时的检查清单:你的 Generator 的输入是不是完整的部分解?Evaluator 评的是不是局面而不是最后一步?如果答案是否,你实现的就不是 ToT。
Thought 粒度决定成败 粒度太粗(「思路 A:用动态规划」)→ 评估器无法判断好坏,因为还没落地。 粒度太细(每个 token 一个节点)→ 树爆炸,成本失控。 经验规则:一个 Thought 应该是「独立可评估、且推进了实质进度」的最小单位。以 24 点游戏为例,一个 Thought 就是一次算式(
4 + 9 = 13),既能立刻校验合法性,又确实缩小了问题。
四、🆚 和 CoT、Self-Consistency 的区别
三者常被混淆,差别在分支发生的时机和有没有中途评估。
| 维度 | CoT | Self-Consistency | ToT |
|---|---|---|---|
| 路径数量 | 1 条 | N 条完整链 | 1 棵树,动态增删 |
| 分支时机 | 无 | 从头就分叉,各走各的 | 每一步都可分叉 |
| 中途评估 | 无 | 无(只在末尾投票) | 每步都评估 |
| 能否回溯 | 否 | 否 | 取决于搜索策略(DFS 会显式回溯,BFS 不回溯) |
| 走错了怎么办 | 一路错到底 | 靠多数票稀释 | 当场剪掉,换分支 |
| 成本 | 1× | N× | 高,且随深度和分支数增长 |
一句话区分:
- CoT:一条路走到黑。
- Self-Consistency:N 条路各走到黑,最后投票。
- ToT:边走边评估,走不通的当场剪掉,换分支。
「回溯」和「并行」都是可选项,不是 ToT 的定义 两个常见的过度概括:
- 不是每种 ToT 都回溯。 原论文同时用了 BFS 和 DFS:24 点和创意写作用 BFS——一层一层往下推、每层只留 top-b,走不通的分支直接被剪掉,并没有「退回上一步」这个动作;填字游戏用 DFS——才有显式的回溯。
- 不是每种实现都物理并行。 「同时铺开多条思路」说的是搜索结构上同时存在多个候选,不代表工程上必须并发调用模型。串行地把 b 个候选逐个生成、逐个评估,同样是 ToT,只是慢一些。
五、⚠️ 核心陷阱:评估函数是整个方法的命门
⚠️ 用 LLM 自评当评估器,却没有校准 错误操作: 直接让模型给每个思路打 0~1 分:「请给这个思路的可行性打分」。
实际结果: 打分密集分布在 0.7~0.9,几乎区分不出好坏;剪枝退化成随机剪枝。更糟的是,模型倾向于给表述流畅的思路高分,而不是给真正可行的思路高分——最后剪掉的往往是写得糙但正确的那条。
原因: LLM 的绝对分数没有校准基准,它不知道 0.7 和 0.8 的客观差别在哪;而流畅度是训练目标里的强信号,可行性不是。
正确做法: 优先级从高到低:
- 能确定性校验的部分一律用代码——能跑代码就跑代码,能算就算,能查 schema 就查。
- 用分类而非打分——原论文在 24 点上就是让模型把状态归成
sure / likely / impossible三档,比连续分数稳定得多。- 用两两比较而非绝对分——「A 和 B 哪个更有希望」的准确率显著高于给 A 打分。原论文在创意写作这类没有客观标准的任务上用的就是投票式比较。
⚠️ 以为 24 点的评估器只是「查算式合不合法」 错误操作: 认为 24 点是可判定问题,所以评估器写成一个校验函数:算式合法就留、不合法就剪。
实际结果: 几乎剪不掉任何东西。因为 Generator 生成的候选基本都是合法算式——
4+9=13、4×9=36、9-4=5全都合法。合法性筛完,该展开的分支一个没少,指数爆炸原封不动,ToT 退化成穷举。原因: 混淆了两个不同的判断。「这一步合不合法」是语法问题,确实可判定且廉价,但没有区分度;ToT 真正需要的是「从这个局面出发还够不够得着 24」——这是前瞻性判断,才是剪枝的依据。原论文的 value prompt 做的正是后者:把剩余数字喂给模型,让它判断能否达到 24,输出
sure / likely / impossible。正确做法: 两层叠加——先用代码做合法性和终止判定(算错了、用错数字、已经等于 24),再用模型或启发式做「还有没有希望」的前瞻评估。只做第一层等于没有评估器;只做第二层则会让明显算错的分支活下来。
顺带一提:24 点确实可以纯暴力枚举求解,根本不需要 LLM。它在论文里的角色是基准任务,用来量化 ToT 相对 CoT 的提升,不是说这类问题该用 ToT 解。
⚠️ 成本失控 错误操作: 分支数 k=5,深度 d=4,不设任何预算上限。
实际结果: 不剪枝时,第 4 层的叶子就有 5⁴ = 625 个,整棵树的节点总数是 1 + 5 + 25 + 125 + 625 = 781。每个节点至少一次生成 + 一次评估,单次问答上千次模型调用,延迟以分钟计。
原因: 每层节点数是 kᵈ,总数是等比数列求和
(k^(d+1) − 1) / (k − 1),量级由最后一层主导,所以仍然是指数增长。注意别把 kᵈ 和总节点数搞混——kᵈ 只是第 d 层的宽度。分支数大时两者差距不大(781 vs 625),但 k=2 这种小分支下差一倍(d=4 时叶子 16、总数 31),估成本时按总数算。
正确做法: 三道闸门一起上:
- Beam Search 固定每层只保留 b 个节点(把指数压成线性
b × k × d);- 设总节点数硬上限,超了就返回当前最优;
- 深度上限 + 早停(一旦某分支达到可接受解就停)。
💡 先问一句:这题真的需要 ToT 吗 ToT 的收益来自「走错了能退回来」。如果任务本身很少走错,或者错了也能靠 Reflexion 事后修,那 CoT + Reflexion 的组合通常比 ToT 便宜一个数量级。ToT 适合那种错了就没法修、必须当场换路的问题。
六、什么时候用
用:
- 数学题、逻辑题、Puzzle(24 点、数独、填字)
- 需要探索多种方案再选优的规划问题
- 有廉价、可靠的中间校验手段的任务(这是关键前提)
不用:
- 单跳事实问答 → 直接答
- 缺信息而非缺思路 → Self-Ask
- 对延迟和成本敏感的线上场景 → ToT 通常跑不起
七、复习重点
复习重点
- 定义:把 CoT 的线性链扩展成可分叉、可评估、可剪枝的树,再用经典搜索算法遍历。
- 节点是 state 不是 thought:
s = [x, z₁…zᵢ],即「原问题 + 走过的全部 thought」这个部分解;thought 是边。评估器评的是局面,不是最后那句话。- 一轮四步:生成候选 → 评估 → 剪枝 → 继续展开。
- 四个必备组件:Thought 粒度定义、Generator、Evaluator、搜索策略。
- 和 Self-Consistency 的关键差别:ToT 每步都评估;Self-Consistency 只在末尾投票,走错了也得走完。回溯是 DFS 变体才有的,不是 ToT 的定义。
- 命门:Evaluator,而且要评「还有没有希望」而不是「这步合不合法」——24 点的 value prompt 判的是剩余数字能否达到 24(
sure / likely / impossible)。别用未校准的 LLM 绝对打分。- 成本:第 d 层宽度是 kᵈ,总节点数是
(k^(d+1)−1)/(k−1)(k=5、d=4 时是 781,不是 625)。必须用 Beam 宽度 + 节点上限 + 早停三道闸门。- 它管哪一层:候选搜索。缺思路才用它;缺信息用 Self-Ask,缺步骤用 Plan-and-Execute。
相关笔记:Agent 推理范式总览|Plan-and-Execute 先规划再执行|Reflexion 反思式自我纠错|Self-Ask 自问自答多跳推理